"""
题目：判断101-200之间有多少个素数，并输出所有素数。
质数（prime number）又称素数，有无限个。
质数定义为在大于1的自然数中，除了1和它本身以外不再有其他因数。
"""

import math


def answer1():
    """
    根据素数定义，一个一个判断
    :return:
    """
    print("输出一", end=":")
    sumCount = 0
    findTimes = 0
    for i in range(101, 2000):
        for j in range(2, i):
            findTimes += 1
            if i % j == 0:
                break
        else:
            print(i, end=",")
            sumCount += 1
    print("共%d个" % sumCount, end=",")
    print("共比较了%d次" % findTimes)


answer1()


def answer2():
    """
    上述判断方法，明显存在效率极低的问题。对于每个数n，其实并不需要从2判断到n-1，我们知道，一个数若可以进行因数分解，
    那么分解时得到的两个数一定是一个小于等于sqrt(n)，一个大于等于sqrt(n)，据此，上述代码中并不需要遍历到n-1，遍历到sqrt(n)即可，
    因为若sqrt(n)左侧找不到约数，那么右侧也一定找不到约数。
    :return:
    """
    print("输出二", end=":")
    sumCount = 0
    findTimes = 0
    for i in range(101, 2000):
        sqrtNum = int(math.sqrt(i))
        for j in range(2, sqrtNum + 1):
            findTimes += 1
            if i % j == 0:
                break
        else:
            print(i, end=",")
            sumCount += 1
    print("共%d个" % sumCount, end=",")
    print("共比较了%d次" % findTimes)


answer2()


def answer3():
    """
        方法（2）应该是最常见的判断算法了，时间复杂度O(sqrt(n))，速度上比方法（1）的O(n)快得多。最近在网上偶然看到另一种更高效的方法，暂且称为方法（3）吧，
    由于找不到原始的出处，这里就不贴出链接了，如果有原创者看到，烦请联系我，必定补上版权引用。下面讲一下这种更快速的判断方法；
    首先看一个关于质数分布的规律：大于等于5的质数一定和6的倍数相邻。例如5和7，11和13,17和19等等；
    证明：令x≥1，将大于等于5的自然数表示如下：
    ······ 6x-1，6x，6x+1，6x+2，6x+3，6x+4，6x+5，6(x+1），6(x+1)+1 ······
    可以看到，不在6的倍数两侧，即6x两侧的数为6x+2，6x+3，6x+4，由于2(3x+1)，3(2x+1)，2(3x+2)，所以它们一定不是素数，再除去6x本身，
    显然，素数要出现只可能出现在6x的相邻两侧。这里有个题外话，关于孪生素数，有兴趣的道友可以再另行了解一下，由于与我们主题无关，暂且跳过。
    这里要注意的一点是，在6的倍数相邻两侧并不是一定就是质数。
    根据以上规律，判断质数可以6个为单元快进，即将方法（2）循环中i++步长加大为6，加快判断速度，代码如下：

    高手无处不在啊

    由上可得，只要从96开始，每6个计算一次
    :return:
    """
    print("输出三", end=":")
    sumCount = 0
    findTimes = 0
    for i in range(102, 2000, 6):
        for num in (i - 1, i + 1):
            sqrtNum = int(math.sqrt(num))
            for j in range(2, sqrtNum + 1):
                findTimes += 1
                if num % j == 0:
                    break
            else:
                print(num, end=",")
                sumCount += 1
    print("共%d个" % sumCount, end=",")
    print("共比较了%d次" % findTimes)


answer3()


def answer4():
    """
    上面的方法，高手还可以改进
    因为上述可得，6x-1和6x+1坑定不会被6x,6x+2,6x+3,6x+4整除，弱它是素数，那么它也是被6x-1或6x+1整除
    所以上面方法，里面的判断也可以跨6来判断
    :return:
    """
    print("输出四", end=":")
    sumCount = 0
    findTimes = 0
    for i in range(102, 2000, 6):
        for num in (i - 1, i + 1):
            sqrtNum = int(math.sqrt(num))
            for j in range(5, sqrtNum + 1, 6):
                findTimes += 1
                if num % j == 0 or num % (j + 2) == 0:
                    break
            else:
                print(num, end=",")
                sumCount += 1
    print("共%d个" % sumCount, end=",")
    print("共比较了%d次" % findTimes)


answer4()


def answer5():
    """
    排除偶数，数组统计
    :return:
    """
    print("输出五", end=":")
    findTimes = 0
    numList = []
    for i in range(101, 2000, 2):
        numList.append(str(i))
        sqrtNum = int(math.sqrt(i))
        for j in range(2, sqrtNum + 1):
            findTimes += 1
            if i % j == 0:
                numList.pop()
                break
    print(",".join(numList), end=",")
    print("共%d个" % len(numList), end=",")
    print("共比较了%d次" % findTimes)


answer5()


class answer6:
    """
    练习迭代器
    """

    def __init__(self):
        """
        构造函数
        """
        self.sumCount = 0
        self.findTimes = 0
        self.startNum = 102
        self.endNum = 2000
        print("输出六", end=":")

    def __iter__(self):
        """
        迭代器
        :return:
        """
        return self

    def __next__(self):
        """
        迭代器next
        :return:
        """
        if self.startNum > self.endNum:
            raise StopIteration
        for num in (self.startNum - 1, self.startNum + 1):
            sqrtNum = int(math.sqrt(num))
            for i in range(5, sqrtNum + 1, 6):
                self.findTimes += 1
                if num % i == 0 or num % (i + 2) == 0:
                    break
            else:
                print(num, end=",")
                self.sumCount += 1
        self.startNum += 6


answer = answer6()
for i in answer:
    pass
print("共%d个" % answer.sumCount, end=",")
print("共比较了%d次" % answer.findTimes)


def answer7():
    """
    练习yield生成器，注意和answer6区域
    """
    print("输出七", end=":")
    startNum = 102
    sumCount = 0
    findTimes = 0
    while startNum < 2000:
        for num in (startNum - 1, startNum + 1):
            sqrtNum = int(math.sqrt(num))
            for i in range(5, sqrtNum + 1, 6):
                findTimes += 1
                if num % i == 0 or num % (i + 2) == 0:
                    break
            else:
                sumCount += 1
                print(num, end=",")
                yield num
        startNum += 6
    print("共%d个" % sumCount, end=",")
    print("共比较了%d次" % findTimes)


for i in answer7():
    pass


def answer8():
    """
    练习数组生成器表达式
    参考：http://blog.csdn.net/u014745194/article/details/70176117
    :return:
    """
    print("输出八", end=":")
    numList = list(filter(lambda x: x not in set([i for i in range(101, 200) for j in range(2, i - 1) if not i % j]),
                          range(101, 200)))
    print(numList, end=",")
    print("共%d个" % len(numList))


answer8()
